package com.teamwings.modules.code.controller;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.collect.Lists;
import com.teamwings.common.constant.FormConstant;
import com.teamwings.common.vo.Result;
import com.teamwings.modules.code.entity.FormTableCode;
import com.teamwings.modules.code.service.IFormTableCodeService;
import com.teamwings.modules.code.vo.FormTableCodeExcelVo;
import com.teamwings.modules.design.service.IDesignService;
import com.teamwings.modules.head.entity.FormTableHead;
import com.teamwings.modules.head.service.IFormTableHeadService;
import com.teamwings.modules.list.entity.FormTableList;
import com.teamwings.modules.list.service.IFormTableListService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.jeecgframework.poi.excel.ExcelImportUtil;
import org.jeecgframework.poi.excel.def.NormalExcelConstants;
import org.jeecgframework.poi.excel.entity.ExportParams;
import org.jeecgframework.poi.excel.entity.ImportParams;
import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Caching;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 前端控制器
 * </p>
 *
 * @author admin
 * @since 2021-05-06
 */
@RestController
@Api(tags = "表单code")
@RequestMapping("/form/code")
@Slf4j
public class CodeController {

    private final static Logger logger = LoggerFactory.getLogger(CodeController.class);

    @Autowired
    private IFormTableCodeService codeService;
    @Autowired
    private IFormTableHeadService headService;
    @Autowired
    private IDesignService designService;
    @Autowired
    private IFormTableListService tableListService;

    /**
     * 导出对应的表单信息
     */
    @ApiOperation(value = "导出对应的表单信息", notes = "导出对应的表单信息")
    @PostMapping(value = "/export")
    public ModelAndView export(@RequestBody String heads, String userName) {
        List<FormTableHead> formTableHeads = JSONArray.parseArray(JSONObject.parseObject(heads).get("heads").toString(), FormTableHead.class);
        LambdaQueryWrapper<FormTableCode> queryWrapper = Wrappers.lambdaQuery();
        //遍历添加查询条件 多个headid和version
        for (FormTableHead formTableHead : formTableHeads) {
            queryWrapper.or(wrapper -> wrapper.eq(FormTableCode::getTableHeadId, formTableHead.getId()).eq(FormTableCode::getTableVersion, formTableHead.getTableVersion()));
        }
        //封装为导入excel的对象
        List<FormTableCodeExcelVo> excelVos = codeService.getCodeWithHead(queryWrapper).stream().map(formTableCode -> {
            FormTableCodeExcelVo vo = new FormTableCodeExcelVo();
            BeanUtils.copyProperties(formTableCode, vo);
            //设置为导出的版本号
            formTableCode.getHead().setTableVersion(formTableCode.getTableVersion());
            vo.setHead(JSONObject.toJSONString(formTableCode.getHead()));
            vo.setRemarks((formTableCode.getRemarks()==null?"":formTableCode.getRemarks()) + "  [导出人：" + userName +
                "，导出时间：" + new Date().toLocaleString() + "，导出版本号：" + formTableCode.getTableVersion() +"]");
            // 如果有对应的设计列表，则一齐导出
            FormTableList tableList = tableListService.getById(formTableCode.getHead().getId());
            if (tableList != null){
                vo.setTableListCode(tableList.getData());
            }
            return vo;
        }).collect(Collectors.toList());

        //Step.2 AutoPoi 导出Excel
        ModelAndView mv = new ModelAndView(new JeecgEntityExcelView());
        //导出文件名称
        mv.addObject(NormalExcelConstants.FILE_NAME, "表单信息");
        mv.addObject(NormalExcelConstants.CLASS, FormTableCodeExcelVo.class);
        ExportParams exportParams = new ExportParams("表单数据", "导出人:" + userName, "导出信息");
        mv.addObject(NormalExcelConstants.PARAMS, exportParams);
        mv.addObject(NormalExcelConstants.DATA_LIST, excelVos);
        return mv;
    }

    /**
     * 解析导入excel信息，返回给前端
     *
     * @param request
     * @return
     * @throws IOException
     */
    @ApiOperation(value = "解析导入excel信息，返回给前端", notes = "解析导入excel信息，返回给前端")
    @PostMapping(value = "/importEx")
    public Result<?> importExcel(HttpServletRequest request) throws IOException {
        MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
        Map<String, MultipartFile> fileMap = multipartRequest.getFileMap();
        // 错误信息
        List<String> errorMessage = new ArrayList<>();

        for (Map.Entry<String, MultipartFile> entity : fileMap.entrySet()) {
            MultipartFile file = entity.getValue();// 获取上传文件对象
            ImportParams params = new ImportParams();
            params.setTitleRows(2);
            params.setHeadRows(1);
            params.setNeedSave(true);
            try {
                //解析excel表
                List<FormTableCodeExcelVo> formTableCodeExcelVos = ExcelImportUtil.importExcel(file.getInputStream(), FormTableCodeExcelVo.class, params);
                return Result.OK(formTableCodeExcelVos);
            } catch (Exception e) {
                errorMessage.add("发生异常：" + e.getMessage());
                log.error(e.getMessage(), e);
                return Result.error("Excel解析有误，请重新导出");
            } finally {
                try {
                    file.getInputStream().close();
                } catch (IOException e) {
                    log.error(e.getMessage(), e);
                }
            }
        }
        return null;
    }

    /**
     * 导入表单信息
     *
     * @param codes
     * @return
     * @throws IOException
     */
    @Caching(evict = {
        @CacheEvict(value = FormConstant.FORM_HEAD_PAGING, key = "'*'"),
    })
    @ApiOperation(value = "导入表单信息", notes = "导入表单信息")
    @PostMapping(value = "/import")
    public Result<?> importCodes(@RequestBody String codes) {

        List<FormTableCodeExcelVo> excelVos = JSONArray.parseArray(JSONObject.parseObject(codes).get("codes").toString(), FormTableCodeExcelVo.class);
        if (excelVos == null) {
            return Result.error("没有对应的表单信息");
        }

        //统计出错条数
        int errorCount = 0;
        List<String> errorCodeIds = Lists.newArrayList();

        for (int i = 0; i < excelVos.size(); i++) {
            try {
                FormTableCode formTableCode = new FormTableCode();
                BeanUtils.copyProperties(excelVos.get(i), formTableCode);
                FormTableHead head = JSON.parseObject(excelVos.get(i).getHead(), FormTableHead.class);
                FormTableHead oldHead = headService.getById(head.getId());

                //判断 head是否已存在
                if (oldHead != null) {
                    //查询最后一个code 追加在后面
                    FormTableCode latestOneCode = (FormTableCode)codeService.getAllOrSpecific(head.getId(),
                        true, "TABLE_VERSION");
                    formTableCode.setTableVersion(latestOneCode.getTableVersion() + 1);
                    //生产环境注释 导入时自动改用导入的表单版本
                    oldHead.setTableVersion(latestOneCode.getTableVersion() + 1);
                    headService.editMain(oldHead);
                } else {
                    head.setTableVersion(1)
                        .setCreateTime(null);
                    //创建head 不创建code 保存原来的tableName
                    Boolean result = headService.saveMain(head, false,true);
                    // 表单的 SourceType 为0 是有数据源 才创建数据库
                    if (result && head.getSourceType() == 0) {
                        //创建数据库表
                        designService.createDesignTable(formTableCode.getTableCode(),head.getTableName());
                        formTableCode.setTableVersion(1);
                    }
                }
                formTableCode.setTableHeadId(head.getId());
                formTableCode.setId(null);
                boolean save = codeService.save(formTableCode);
                // 如果保存成功并且有设计列表的代码则保存设计列表,有侧覆盖
                if (save && excelVos.get(i).getTableListCode() != null){
                    FormTableList tableList = new FormTableList();
                    tableList.setId(head.getId())
                             .setData(excelVos.get(i).getTableListCode());
                    tableListService.saveOrUpdate(tableList);
                }
            } catch (Exception e) {
                logger.error("CodeController:import报错：" + e.getMessage());
                errorCount++ ;
                //获取保存时发生错误的codeid
                errorCodeIds.add(excelVos.get(i).getId());
            }
        }
        if (errorCount == 0){
            return Result.OK("全部导入成功");
        }
        return Result.error("导入成功，其中有"+errorCount+"条表单保存时发生错误", errorCodeIds);
    }

}
